# enhanced_app.py - 强化版Flask后端，解决CORS和连接问题
from flask import Flask, request, jsonify, make_response
import os
import json
import datetime
import logging
from werkzeug.utils import secure_filename
from model_runner import run_deepfake_model

# 配置日志
logging.basicConfig(level=logging.INFO, 
                    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

app = Flask(__name__)

# 更强的CORS响应头处理
@app.after_request
def add_cors_headers(response):
    # 允许任何来源的请求
    origin = request.headers.get('Origin', '*')
    response.headers.add('Access-Control-Allow-Origin', origin)
    # 允许所有头部
    response.headers.add('Access-Control-Allow-Headers', 
                         'Content-Type,Authorization,X-Requested-With,Accept,Origin')
    # 允许所有方法
    response.headers.add('Access-Control-Allow-Methods', 
                         'GET,PUT,POST,DELETE,OPTIONS')
    # 允许凭证
    response.headers.add('Access-Control-Allow-Credentials', 'true')
    # 设置预检请求的有效期为3600秒
    response.headers.add('Access-Control-Max-Age', '3600')
    # 设置内容类型
    if 'Content-Type' not in response.headers:
        response.headers.add('Content-Type', 'application/json')
    return response

# 对所有OPTIONS请求进行特殊处理
@app.route('/', defaults={'path': ''}, methods=['OPTIONS'])
@app.route('/<path:path>', methods=['OPTIONS'])
def options_handler(path):
    response = make_response('', 200)
    # 返回一个空响应，浏览器会使用此响应的头部进行后续判断
    return response

UPLOAD_FOLDER = 'upload'
HISTORY_FILE = os.path.abspath('history.json')  # 使用绝对路径
logger.info(f"历史文件路径: {HISTORY_FILE}")
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov'}

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024  # 限制上传文件大小为50MB

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def load_history():
    if os.path.exists(HISTORY_FILE):
        logger.info(f"历史文件存在，正在加载: {HISTORY_FILE}")
        try:
            with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
                data = json.load(f)
                logger.info(f"成功加载历史记录: {len(data)}条记录")
                return data
        except Exception as e:
            logger.error(f"加载历史记录失败: {str(e)}")
            # 如果JSON解析失败，尝试创建新文件
            try:
                with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
                    json.dump([], f)
                logger.info("创建了新的空历史文件")
                return []
            except Exception as write_error:
                logger.error(f"创建新历史文件失败: {str(write_error)}")
            return []
    else:
        logger.warning(f"历史文件不存在: {HISTORY_FILE}")
        # 创建空的历史文件
        try:
            with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
                json.dump([], f)
            logger.info("创建了新的空历史文件")
        except Exception as e:
            logger.error(f"创建新历史文件失败: {str(e)}")
        return []

def save_history(history):
    try:
        with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
            json.dump(history, f, ensure_ascii=False)
        logger.info(f"历史记录保存成功，共{len(history)}条记录")
    except Exception as e:
        logger.error(f"保存历史记录失败: {str(e)}")

@app.route('/')
def index():
    logger.info("访问首页")
    return "✅ Flask 后端运行成功 (强化版) - AutoDL环境"

# 添加简单的健康检查端点
@app.route('/ping')
def ping():
    logger.info("健康检查")
    return jsonify({
        "status": "ok", 
        "time": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        "server": "enhanced_app.py"
    })

@app.route('/upload', methods=['POST', 'OPTIONS'])
def upload_video():
    # 处理OPTIONS预检请求
    if request.method == 'OPTIONS':
        response = make_response('', 200)
        return response
        
    logger.info(f"收到上传请求，内容类型: {request.content_type}")
    logger.info(f"请求头: {dict(request.headers)}")
    
    # 特殊处理没有文件的情况
    if 'video' not in request.files:
        logger.warning("没有找到视频文件")
        return jsonify({'error': '没有找到视频文件'}), 400
    
    video = request.files['video']
    if not video or video.filename == '':
        logger.warning("文件名为空")
        return jsonify({'error': '文件名为空'}), 400
        
    if not allowed_file(video.filename):
        logger.warning(f"不允许的文件类型: {video.filename}")
        return jsonify({'error': f'不允许的文件类型，仅支持: {", ".join(ALLOWED_EXTENSIONS)}'}), 400
    
    filename = secure_filename(video.filename)
    save_path = os.path.join(UPLOAD_FOLDER, filename)
    
    try:
        video.save(save_path)
        logger.info(f"视频已保存: {save_path}")
    except Exception as e:
        logger.error(f"保存视频失败: {str(e)}")
        return jsonify({'error': f'保存视频失败: {str(e)}'}), 500

    # 调用模型识别
    try:
        score = run_deepfake_model(os.path.abspath(save_path))
        if score is None:
            logger.error("模型识别返回空结果")
            return jsonify({'error': '模型识别失败'}), 500
        
        # 将阈值设置为0.25 - 根据历史数据分析得出的更合适的阈值
        result = "伪造" if score > 0.25 else "真实"
        logger.info(f"识别结果: {result}, 得分: {score}")
    except Exception as e:
        logger.error(f"模型识别过程出错: {str(e)}")
        return jsonify({'error': f'模型识别失败: {str(e)}'}), 500
    
    # 保存历史记录
    try:
        history = load_history()
        new_record = {
            'filename': filename,
            'score': score,
            'result': result,
            'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        }
        history.append(new_record)
        save_history(history)
        logger.info(f"添加新记录: {new_record}")
    except Exception as e:
        logger.error(f"保存历史记录时出错: {str(e)}")
        # 继续执行，不要因为历史记录保存失败而影响主流程
    
    return jsonify({
        'score': score, 
        'result': result,
        'filename': filename,
        'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    })

@app.route('/history', methods=['GET', 'OPTIONS'])
def get_history():
    # 处理OPTIONS预检请求
    if request.method == 'OPTIONS':
        response = make_response('', 200)
        return response
        
    logger.info("正在获取历史记录")
    try:
        history = load_history()
        logger.info(f"返回历史记录，共{len(history)}条")
        # 返回最新的记录在前面
        sorted_history = sorted(history, key=lambda x: x['time'], reverse=True)
        return jsonify(sorted_history)
    except Exception as e:
        logger.error(f"获取历史记录时出错: {str(e)}")
        return jsonify([])  # 返回空数组而不是出错

# 添加诊断信息接口
@app.route('/debug', methods=['GET'])
def debug_info():
    info = {
        "server_time": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        "python_version": os.sys.version,
        "upload_folder": os.path.abspath(UPLOAD_FOLDER),
        "history_file": HISTORY_FILE,
        "file_exists": os.path.exists(HISTORY_FILE),
        "upload_dir_exists": os.path.exists(UPLOAD_FOLDER),
        "server_ip": request.host,
        "client_ip": request.remote_addr,
        "request_method": request.method,
        "request_headers": dict(request.headers)
    }
    return jsonify(info)

# 添加一个新的诊断端点
@app.route('/model_diagnostics', methods=['GET'])
def model_diagnostics():
    """分析历史记录中的模型分数分布"""
    try:
        history = load_history()
        if not history:
            return jsonify({"error": "没有历史记录可分析"})
            
        # 提取所有分数
        scores = [record.get('score', 0) for record in history if 'score' in record]
        
        if not scores:
            return jsonify({"error": "没有找到有效的分数记录"})
            
        # 分析分数分布
        diagnostics = {
            "分数总数": len(scores),
            "最小分数": min(scores),
            "最大分数": max(scores),
            "平均分数": sum(scores) / len(scores),
            "分数中位数": sorted(scores)[len(scores)//2],
            "分数分布": {
                "0.0-0.1": len([s for s in scores if 0.0 <= s < 0.1]),
                "0.1-0.2": len([s for s in scores if 0.1 <= s < 0.2]),
                "0.2-0.3": len([s for s in scores if 0.2 <= s < 0.3]),
                "0.3-0.4": len([s for s in scores if 0.3 <= s < 0.4]),
                "0.4-0.5": len([s for s in scores if 0.4 <= s < 0.5]),
                "0.5-0.6": len([s for s in scores if 0.5 <= s < 0.6]),
                "0.6-0.7": len([s for s in scores if 0.6 <= s < 0.7]),
                "0.7-0.8": len([s for s in scores if 0.7 <= s < 0.8]),
                "0.8-0.9": len([s for s in scores if 0.8 <= s < 0.9]),
                "0.9-1.0": len([s for s in scores if 0.9 <= s <= 1.0]),
            },
            "不同阈值下伪造判断数": {
                "阈值0.1": len([s for s in scores if s > 0.1]),
                "阈值0.2": len([s for s in scores if s > 0.2]),
                "阈值0.3": len([s for s in scores if s > 0.3]),
                "阈值0.4": len([s for s in scores if s > 0.4]),
                "阈值0.5": len([s for s in scores if s > 0.5]),
            }
        }
        
        return jsonify(diagnostics)
    except Exception as e:
        logger.error(f"分析模型诊断时出错: {str(e)}")
        return jsonify({"error": f"分析失败: {str(e)}"})

if __name__ == '__main__':
    print("\n" + "="*50)
    print("增强版Flask后端服务启动中...")
    print("="*50 + "\n")
    
    logger.info("Flask服务启动，端口: 6006")
    # 增加线程数量，确保能够处理并发请求
    app.run(host='0.0.0.0', port=6006, debug=True, threaded=True) 